/*
 * Copyright (c) 2024-present HBIS Digital Technology Co.,Ltd. All rights reserved.
 */
package com.hbisdt.cet.sample.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * Redis配置
 *
 * @author : 教学示例
 * @version : 1.0
 * @date : 2024-12-12 15:31
 */
@Configuration
public class RedisConfig {
    /**
     * 配置并返回一个 RedisTemplate 实例，用于操作 Redis 数据库。
     * 该模板支持对 Redis 的各种操作，并且使用 Jackson2JsonRedisSerializer 来序列化和反序列化 Redis 的 value 值。
     * 默认情况下，key 和 hash key 使用 String 的序列化方式，而 value 和 hash value 使用 Jackson 的序列化方式。
     *
     * @param connectionFactory Redis 连接工厂，用于创建 Redis 连接。
     * @return 配置好的 RedisTemplate 实例，用于操作 Redis 数据库。
     * @author : 教学示例
     */
    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        // 设置 Redis 连接工厂
        template.setConnectionFactory(connectionFactory);

        // 配置 Jackson 对象映射器，用于序列化和反序列化
        ObjectMapper objectMapper = new ObjectMapper();
        // 设置ObjectMapper的可见性，允许序列化所有字段（包括private和public）
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 激活默认类型信息，用于序列化非 final 类型的对象
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);

        // 创建GenericJackson2JsonRedisSerializer序列化器
        GenericJackson2JsonRedisSerializer value_jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(objectMapper);
        // 创建StringRedisSerializer序列化器
        StringRedisSerializer key_stringRedisSerializer = new StringRedisSerializer();

        // 设置 key 和 value 的序列化方式
        template.setKeySerializer(key_stringRedisSerializer);
        template.setValueSerializer(value_jackson2JsonRedisSerializer);
        // 设置 hash key 和 hash value 的序列化方式
        template.setHashKeySerializer(key_stringRedisSerializer);
        template.setHashValueSerializer(value_jackson2JsonRedisSerializer);
        return template;
    }

    /**
     * 创建一个Redis缓存管理器Bean，用于管理Redis缓存配置。
     * 该缓存管理器使用Jackson2JsonRedisSerializer来序列化和反序列化缓存值，
     * 并配置了缓存的过期时间、键和值的序列化方式，以及是否缓存空值等。
     *
     * @param connectionFactory Redis连接工厂，用于创建与Redis服务器的连接。
     * @return 配置好的RedisCacheManager实例，用于管理Redis缓存。
     */
    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        // 配置 Jackson 对象映射器，用于序列化和反序列化
        ObjectMapper objectMapper = new ObjectMapper();
        // 设置ObjectMapper的可见性，允许序列化所有字段（包括private和public）
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 激活默认类型信息，用于序列化非final类型的对象
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);

        // 创建GenericJackson2JsonRedisSerializer序列化器
        GenericJackson2JsonRedisSerializer value_jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(objectMapper);
        // 创建StringRedisSerializer序列化器
        StringRedisSerializer key_stringRedisSerializer = new StringRedisSerializer();

        // 配置Redis缓存的基本设置
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                // 设置缓存条目的过期时间为1天
                .entryTtl(java.time.Duration.ofDays(1))
                // 使用StringRedisSerializer序列化缓存键
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(key_stringRedisSerializer))
                // 使用GenericJackson2JsonRedisSerializer序列化缓存值
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(value_jackson2JsonRedisSerializer))
                // 禁止缓存空值
                .disableCachingNullValues();
        // 使用配置好的RedisCacheConfiguration创建RedisCacheManager
        RedisCacheManager cacheManager = RedisCacheManager.builder(connectionFactory).cacheDefaults(config).build();
        return cacheManager;
    }
}
